/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "hc32f4a0_usart.h"
#include "common/hc32f4a0_errno.h"
#include "core/include/hc32f4a0_pwc.h"
#include "core/include/hc32f4a0_clk.h"
#include "core/include/hc32f4a0_intc.h"
#include <string.h>
#include <stdlib.h>

/*******************************************************************************
 * Macro operate
 ******************************************************************************/
/* \brief USART 寄存器清除标志位定义*/
#define USART_CR1_CLR_FLAG_MASK     (USART_CR1_CPE    |     \
                                     USART_CR1_CORE   |     \
                                     USART_CR1_CFE    |     \
                                     USART_CR1_CRTOF  |     \
                                     USART_CR1_CBE    |     \
                                     USART_CR1_CWKUP  |     \
                                     USART_CR1_CLBD)

#define IS_USART_PCLK_DIV(x)       ((USART_PCLK_DIV1 == (x))  || \
                                    (USART_PCLK_DIV4 == (x))  || \
                                    (USART_PCLK_DIV16 == (x)) || \
                                    (USART_PCLK_DIV64 == (x)))


/*******************************************************************************
 * Static
 ******************************************************************************/
/* \brief 支持的波特率*/
static const uint32_t __g_typical_baudrate[] = {
    460,
    500,
    600,
    1200,
    2400,
    4800,
    9600,
    14400,
    19200,
    38400,
    43000,
    56000,
    57600,
    76800,
    115200,
    128000,
    230400,
    256000,
    460800,
    600000,
    750000,
    921600,
    1000000,
    2000000
};

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief 串口寄存器检查
 */
static int __usart_reg_chk(struct hc32f4a0_usart_reg *p_uart_reg){
    if (p_uart_reg == NULL) {
        return -EINVAL;
    }
    if ((p_uart_reg != HC32F4A0_USART1) &&
            (p_uart_reg != HC32F4A0_USART2) &&
            (p_uart_reg != HC32F4A0_USART3) &&
            (p_uart_reg != HC32F4A0_USART4) &&
            (p_uart_reg != HC32F4A0_USART5) &&
            (p_uart_reg != HC32F4A0_USART6) &&
            (p_uart_reg != HC32F4A0_USART7) &&
            (p_uart_reg != HC32F4A0_USART8) &&
            (p_uart_reg != HC32F4A0_USART9) &&
            (p_uart_reg != HC32F4A0_USART10)) {
        return -EINVAL;
    }
    return 0;
}

/**
 * \brief 检查波特率参数是否合法
 */
static int __usart_baudrate_chk(uint32_t baudrate){
    int i;

    for (i = 0;i < NELEMENTS(__g_typical_baudrate); i++){
        if (__g_typical_baudrate[i] == baudrate) {
            return 0;
        }
    }
    return -EINVAL;
}

/**
 * \brief 时钟同步波特率计算
 */
static int __clk_sync_baudrate_calc(const struct hc32f4a0_usart_reg *p_usart,
                                    uint32_t                         usart_clk,
                                    uint32_t                         baudrate,
                                    uint32_t                        *p_brr_val,
                                    uint32_t                        *p_fract_en,
                                    float                           *p_err){
    uint32_t C;
    uint32_t B;
    float    div;
    uint64_t tmp;
    uint64_t dividend;
    uint32_t div_integer;
    uint32_t div_fraction = 0UL;
    float    err;
    int      ret          = 0;

    C = usart_clk;
    B = baudrate;

    if ((C > 0UL) && (B > 0UL)) {
        /* 时钟同步模式波特率整数计算公式:
         *          B = C / (4 * (div_integer + 1))
         *          div_integer = (C / (B * 4)) - 1*/
        div = ((float)C / ((float)B * 4.0F)) - 1.0F;
        div_integer = (uint32_t)div;
        if ((div <= 0.0F) || (div_integer > 0xFF)) {
            return -EINVAL;
        }

        tmp = (uint64_t)((uint64_t)4U * ((uint64_t)div_integer + (uint64_t)1UL) * (uint64_t)B);

        if (p_usart != HC32F4A0_USART10) {
            if ((div - (float)div_integer) > 0.00001F) {
                /* 时钟同步模式波特率小数计算公式:
                 *      B = C * (128 + div_fraction) / (4 * (div_integer + 1) * 256)
                 *      div_fraction = 256 * (4 * (div_integer + 1) * B / C - 128  */
                div_fraction = (uint32_t)(256UL * tmp / C - 128UL);
                if (div_fraction > 0x7FUL) {
                    ret = -EINVAL;
                }
            }
        }

        if (0 == ret) {
            *p_fract_en = (div_fraction > 0UL) ? USART_CR1_FBME : 0UL;
            *p_brr_val  = div_fraction + (uint32_t)(div_integer << USART_BRR_DIV_INTEGER_POS);

            if (NULL != p_err) {
                if (0UL == div_fraction) {
                    /* E(%) = C / (4 * (div_integer + 1) * B) - 1 */
                    err = (float)((float)C / (float)tmp) - 1.0F;
                } else {
                    /* E(%) = C * (128 + div_fraction) / (4 * (div_integer + 1) * B * 256) - 1 */
                    tmp *= (uint64_t)256UL;
                    dividend = (uint64_t)C * ((uint64_t)128UL + (uint64_t)div_integer);
                    err = (float)((float)(dividend) / (float)(tmp)) - 1.0F;
                }

                *p_err = err;
            }
        }
    } else {
        ret = -EINVAL;
    }

    return ret;
}

/**
 * \brief USART 波特率计算
 */
static int __usart_baudrate_set(struct hc32f4a0_usart_reg *p_usart,
                                uint32_t                   pclk_freq,
                                uint32_t                   baudrate){
    uint8_t  over8   = 0;
    uint32_t t32     = 0;
    uint64_t t64     = 0;
    float    div     = 0.0;
    int      ret     = 0;
    uint32_t usart_div;
    uint32_t div_integer;
    uint32_t div_fraction;

    /* 获取时钟分频*/
    t32 = READ_REG32(p_usart->PR) & USART_PR_PSC;
    if (t32 == 0) {
        usart_div = 1;
    } else if (t32 == 1) {
        usart_div = 4;
    } else if (t32 == 2) {
        usart_div = 16;
    } else if (t32 == 3) {
        usart_div = 64;
    } else {
        return -EPERM;
    }
    /* 获取一位数据传输期间的基本时钟数*/
    over8 = (p_usart->CR1 & USART_CR1_OVER8)? 1 : 0;
    while (1) {
        /* UART 模式波特率正数计算公式::
         * baudrate = (pclk_freq / usart_div) / (8 * (2 - over8) * (div + 1))
         * div = ((pclk_freq / usart_div) / (baudrate * 8 * (2 - over8))) - 1 */
        div = ((float)(pclk_freq / usart_div) / ((float)baudrate * 8.0F * (2.0F - (float)over8))) - 1.0F;
        if (div > 0 && div <= 255) {
            break;
        }
        if (div < 0) {
            if ((usart_div == 1) && (over8 != 1)) {
                over8     = 1;
                t32       = 3;
                usart_div = 64;
            } else {
                t32--;
            }
        } else {
            if ((usart_div == 3) && (over8 != 0)) {
                over8     = 0;
                t32       = 0;
                usart_div = 1;
            } else {
                t32++;
            }
        }
        if (t32 == 0) {
            usart_div = 1;
        } else if (t32 == 1) {
            usart_div = 4;
        } else if (t32 == 2) {
            usart_div = 16;
        } else if (t32 == 3) {
            usart_div = 64;
        } else {
            ret = -EPERM;
            break;
        }
    }
    div_integer = (uint32_t)(div);
    t64         = (uint64_t)((uint64_t)8UL * ((uint64_t)2UL - (uint64_t)over8) * \
                  ((uint64_t)div_integer + (uint64_t)1UL) * (uint64_t)baudrate);
    if ((p_usart != HC32F4A0_USART5) && \
        (p_usart != HC32F4A0_USART10)) {

        if ((div - (float)div_integer) > 0.00001F) {
            /* UART 模式波特率小数计算公式:
             *      baudrate = C * (128 + div_fraction) / (8 * (2 - over8) * (div_integer + 1) * 256)
             *      div_fraction = (256 * (8 * (2 - over8) * (div_integer + 1) * B) / C) - 128  */
            div_fraction = (uint32_t)(256UL * t64 / (pclk_freq / usart_div) - 128UL);
            if (div_fraction > 0x7FUL) {
                ret = -EPERM;
            }
        }
    }

    if (ret == 0) {
        if (over8) {
            SET_REG32_BIT(p_usart->CR1, USART_CR1_OVER8);
        } else {
            CLEAR_REG32_BIT(p_usart->CR1, USART_CR1_OVER8);
        }
        if (div_fraction > 0) {
            SET_REG32_BIT(p_usart->CR1, USART_CR1_FBME);
        } else {
            CLEAR_REG32_BIT(p_usart->CR1, USART_CR1_FBME);
        }
        WRITE_REG32(p_usart->PR, (t32 & 0x3));
        WRITE_REG32(p_usart->BRR, (div_integer << 8) | div_fraction);
    }

    return 0;
}

/**
 * \brief USART 启动
 *
 * \param[in] p_usart_reg USART 寄存器
 *
 * \retval 成功返回 0
 */
int usart_start(struct hc32f4a0_usart_reg *p_usart_reg){
    if (__usart_reg_chk(p_usart_reg)) {
        return -EINVAL;
    }

    p_usart_reg->CR1 |= (USART_RX | USART_INT_RX | USART_TX);

    return 0;
}

/**
 * \brief USART 停止
 *
 * \param[in] p_usart_reg USART 寄存器
 *
 * \retval 成功返回 0
 */
int usart_stop(struct hc32f4a0_usart_reg *p_usart_reg){
    if (__usart_reg_chk(p_usart_reg)) {
        return -EINVAL;
    }

    p_usart_reg->CR1 &= (~(USART_RX | USART_INT_RX | USART_TX));

    return 0;
}

/**
 * \brief USART 波特率设置
 *
 * \param[in]  p_usart_reg USART 串口寄存器
 * \param[in]  baudrate    要设置的波特率
 * \param[out] p_err       返回错误
 *
 * \retval 成功返回 0
 */
int usart_baudrate_set(struct hc32f4a0_usart_reg *p_usart_reg,
                       uint32_t                   baudrate,
                       float                     *p_err){
    uint32_t mode;
    uint32_t brr_val   = 0;
    uint32_t fract_en  = 0;
    uint32_t usart_clk;
    uint32_t usart_div;
    uint32_t pclk_freq = 0;
    int      ret;

    if ((__usart_baudrate_chk(baudrate)) || (__usart_reg_chk(p_usart_reg))) {
        return -EINVAL;
    }

    /* 获取 USART 时钟分频*/
    usart_div = 1 << ((p_usart_reg->PR & USART_PR_PSC) * 2);
    /* 获取 PCLK*/
    pclk_freq = sys_clk_pclk_get();
    /* 获取 USART 时钟*/
    usart_clk = pclk_freq / usart_div;

    mode = p_usart_reg->CR3 & USART_CR3_SCEN;
    /* 智能卡模式*/
    if (mode > 0UL) {
       //todo
    } else {
        mode = p_usart_reg->CR1 & USART_CR1_MS;
        if (mode > 0) {
            /* 时钟同步*/
            ret = __clk_sync_baudrate_calc(p_usart_reg, usart_clk, baudrate, &brr_val, &fract_en, p_err);
        } else {
            /* UART*/
            ret =  __usart_baudrate_set(p_usart_reg, pclk_freq, baudrate);
        }
    }
    return ret;
}

/**
 * \brief USART 发送函数
 *
 * \param[in] p_usart_reg USART 寄存器
 * \param[in] data        要发送的字节数据
 *
 * \retval 成功返回 1
 */
int usart_byte_write(struct hc32f4a0_usart_reg *p_usart_reg, uint8_t data){
    uint32_t  time_out = 5000;

    if (__usart_reg_chk(p_usart_reg)) {
        return -EINVAL;
    }

    WRITE_REG32(p_usart_reg->DR, (data & 0x01FFUL));
    while ((!(p_usart_reg->SR & USART_FLAG_TXE)) && (--time_out));

    if (time_out == 0) {
        return -ETIME;
    }

    return 1;
}

/**
 * \brief USART 字节读函数
 *
 * \param[in] p_usart_reg USART 寄存器
 * \param[in] p_data      要接收的字节数据缓存
 *
 * \retval 成功返回 1
 */
int usart_byte_read(struct hc32f4a0_usart_reg *p_usart_reg, uint8_t *p_data){
    if ((__usart_reg_chk(p_usart_reg)) || (p_data == NULL)) {
        return -EINVAL;
    }

    *p_data = (READ_REG32(p_usart_reg->DR) >> USART_DR_RDR_POS);

    return 0;
}

/**
 * \brief USART 初始化
 *
 * \param[in] p_usart_reg USART 寄存器
 * \param[in] p_cfg       USART 配置
 *
 * \retval 成功返回 0
 */
int usart_init(struct hc32f4a0_usart_reg *p_usart_reg, struct usart_cfg *p_cfg){
    int ret = 0;

    if ((p_cfg == NULL) || (__usart_reg_chk(p_usart_reg))) {
        return -EINVAL;
    }

    /* 先清除控制寄存器 1 */
    WRITE_REG32(p_usart_reg->CR1, USART_CR1_CLR_FLAG_MASK);

    /* 设置控制寄存器 1 */
    WRITE_REG32(p_usart_reg->CR1, (p_cfg->parity |
                                   p_cfg->data_width |
                                   p_cfg->oversampling_bits |
                                   p_cfg->bit_direction |
                                   p_cfg->noise_filter_state |
                                   p_cfg->sb_detect_polarity));

    /* 设置控制寄存器 2 */
    WRITE_REG32(p_usart_reg->CR2, (USART_CR2_BIT9 |
                                   USART_CR2_BIT10 |
                                   p_cfg->clk_mode |
                                   p_cfg->stop_bit));

    /* 设置控制寄存器3，无硬件流控制 */
    WRITE_REG32(p_usart_reg->CR3, p_cfg->hw_flow_ctrl);

    /* 设置 LBMC */
    WRITE_REG32(p_usart_reg->LBMC, 0UL);


    if (USART_EXTCLK != p_cfg->clk_mode) {
        if (!IS_USART_PCLK_DIV(p_cfg->pclk_div)) {
            return -EINVAL;
        }

        /* Set PR */
        WRITE_REG32(p_usart_reg->PR, p_cfg->pclk_div);

        /* 设置波特率 */
        ret = usart_baudrate_set(p_usart_reg, p_cfg->baudrate, NULL);
    }

    return ret;
}

/**
 * \brief USART 反初始化
 *
 * \param[in] p_usart_reg USART 寄存器
 */
void usart_deinit(struct hc32f4a0_usart_reg *p_usart_reg){
    WRITE_REG32(p_usart_reg->CR1, USART_CR1_CLR_FLAG_MASK);
    WRITE_REG32(p_usart_reg->PR, 0x00000000UL);
    WRITE_REG32(p_usart_reg->BRR, 0x0000FF00UL);
    WRITE_REG32(p_usart_reg->CR1, 0x80000000UL);
    WRITE_REG32(p_usart_reg->CR2, 0x00000600UL);
    WRITE_REG32(p_usart_reg->CR3, 0x00000000UL);
    WRITE_REG32(p_usart_reg->LBMC, 0x00000000UL);
}


















